#pragma once
#include"Logger.hpp"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<cstdlib>
#include<cstring>
#include <arpa/inet.h>
#include<strings.h>
#include<functional>


const int gsockiddefault=-1;

using callback_t=std::function<std::string \
    (const std::string& word,const std::string &whoip,uint16_t whoport)>;

class DictServer
{
public:
    DictServer(uint16_t port,callback_t cb)
        :_sockid(gsockiddefault),
        _port(port),
        _cb(cb),
        _isrunning(false)
    {}
    void Init()
    {
        _sockid=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockid<0)
        {
            LOG(Loglevel::FATAL)<<"create socket error";
            exit(1);
        }
        LOG(Loglevel::INFO)<<"create socket success: "<<_sockid;

        struct sockaddr_in sd;
        bzero(&sd,sizeof(sd));
        sd.sin_family=AF_INET;
        sd.sin_port=htons(_port);
        sd.sin_addr.s_addr=htonl(INADDR_ANY);
        int n=bind(_sockid,(struct sockaddr*)&sd,sizeof(sd));
        if(n<0)
        {
            LOG(Loglevel::FATAL)<<"bind socket error";
            exit(1);
        }
        LOG(Loglevel::INFO)<<"bind socket success: "<<_sockid;

    }
    void Start()
    {
        _isrunning=true;
        while(_isrunning)
        {
            char buffer[1024];
            buffer[0]=0;
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            ssize_t n=recvfrom(_sockid,buffer,sizeof(buffer),
                0,(struct sockaddr*)&peer,&len);
            if(n > 0)
            {
                buffer[n]=0;
                uint16_t clientport = ntohs(peer.sin_port);
                std::string clientip = inet_ntoa(peer.sin_addr);

                LOG(Loglevel::DEBUG)<<"["<<clientip<<
                    ":"<<clientport<<"]#"<<buffer;

                std::string t=_cb(buffer,clientip,clientport);
                std::string echo_string = "server echo# ";
                echo_string += t;
                sendto(_sockid,echo_string.c_str(),
                    echo_string.size(),0,(struct sockaddr*)&peer,len);
            }
        }
        _isrunning=false;
    }
    void Stop()
    {
        _isrunning=false;
    }
    ~DictServer()
    {}
private:
    int _sockid;
    uint16_t _port;
    callback_t _cb;
    bool _isrunning;
};